Матч
417, Тройной прыжок (TripleJump)
Дивизион 2,
Уровень 3
Тройной прыжок совершается
следующим образом. Прыгун разгоняется, добегает до определенной отметки и
совершает три последовательных прыжка. Победителем является тот, чья суммарная
длина прыжков наибольшая.
Вы прыгаете последним. Все Ваши
соперники уже совершили прыжки, их результаты заданы в массиве opponents.
Первый свой прыжок Вы уже
совершили, его длина равна first. Длина
каждого из оставшихся прыжков может с равной вероятностью принимать любое
значение из отрезка [lower, upper], и не обязательно быть целым. Вы
хотите вычислить вероятность того, что займете i - ое место. Необходимо построить массив длины n + 1 (n равно числу соперников), i
-ый элемент которого (индексация массива начинается с 0) содержит вероятность
того, что Вы займете (i + 1) - ое место. Место, занятое
Вами, равняется единице плюс количество соперников, которые прыгнули дальше
Вас.
Класс: TripleJump
Метод: vector<double>
getProbabilities(int lower, int upper,
int first, vector<int> opponents)
Ограничения: 1 £ lower £ 1000,
lower £ upper £ 1000, lower £ first £ upper, opponents содержит
от 1 до 50 элементов, 1 £
opponents[i] £ 3000.
Вход. Целые значения lower, upper , first и массив длин прыжков opponents.
Выход. Массив, содержащий вероятности того, что Вы займете первое,
второе, …, последнее место.
Пример входа
lower |
upper |
first |
opponents |
1 |
2 |
1 |
{1,2,3,4} |
3 |
7 |
5 |
{9,9,19,19,19} |
1 |
10 |
5 |
{1,2,3,5,10,11,12,19} |
Пример выхода
{0.5, 0.5, 0.0, 0.0, 0.0}
{0.0, 0.0, 0.0, 1.0, 0.0, 0.0}
{0.2222, 0.6235, 0.0556, 0.0432, 0.0556, 0.0, 0.0, 0.0, 0.0}
РЕШЕНИЕ
вероятность
Отнимем величину первого прыжка
от всех результатов прыжков соперников, таким образом сведя задачу к “двойному”
прыжку. Из условия задачи следует, что длина каждого прыжка является
независимой случайной величиной, равномерно распределенной на отрезке [lower, upper]. Сумма двух прыжков также является случайной величиной,
определенной на отрезке [2*lower, 2*upper]. Но она уже не будет равномерно
распределенной.
Определим случайную величину F(z) = {сумма двух прыжков не более z}. F(z) пропорционально площади области квадрата под прямой z = x
+ y, изображенной красным цветом.
Функция распределения F(z)имеет вид:
Отсортируем длины прыжков
соперников по убыванию. Вероятность занять первое место равна 1 –
F(opponents[0]). Вероятность занять второе место равна F(opponents[0]) –
F(opponents[1]) и так далее. Вероятность занять последнее место равна
F(opponents[n – 1]), где n – количество соперников.
ПРОГРАММА
#include <cstdio>
#include <vector>
#include <set>
#include <algorithm>
using namespace std;
double f(double lower, double upper, double
z)
{
if (z <= 2 * lower) return
0.0;
if (z <= lower + upper) return
(z – 2 * lower)
* (z - 2*lower) / 2 /
(upper-lower) / (upper - lower);
if (z <= 2 * upper) return
1 - (z – 2 * upper)
* (z – 2 * upper)
/ 2 /
(upper-lower) / (upper
- lower);
return 1.0;
}
class TripleJump
{
public:
vector<double> getProbabilities(int lower, int upper,
int first,
vector<int> opponents)
{
int i, n = (int)opponents.size();
vector<double> res(n + 1, 0);
for(i = 0;
i < n; i++) opponents[i] -= first;
sort(opponents.begin(),opponents.end(),greater<int>());
res[0] = 1 - f(lower,upper,opponents[0]);
res[n] = f(lower,upper,opponents[n-1]);
for(i = 1; i < n; i++)
res[i] = f(lower,upper,opponents[i-1]) - f(lower,upper,opponents[i]);
return res;
}
};